package com.firexxx.vp.domain.vp;

import com.firexxx.vp.domain.vp.single.Age;
import com.firexxx.vp.domain.vp.single.Gender;
import com.firexxx.vp.domain.vp.single.mlvdata.MlvModelData;
import com.firexxx.vp.utils.MatrixUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.math3.linear.RealMatrix;
import org.springframework.data.annotation.Transient;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.validation.constraints.NotNull;

/**
 * @description: TODO
 * @throws:
 * @author: zhuangzhang2
 * @date: 2019/12/19 10:06
 */
@Embeddable
@Getter
@NoArgsConstructor
public class VoicePrintFeature {

    private final static RealMatrix lppSexWeightMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/sex/lpp_sex_200_10_20181009").getPath(),
            200, 10, "utf-8");

    private final static RealMatrix femaleModelMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/sex/model_female_10_1_20181009").getPath(),
            10, 1, "utf-8").transpose();

    private final static RealMatrix maleModelMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/sex/model_male_10_1_20181009").getPath(),
            10, 1, "utf-8").transpose();

    private final static RealMatrix lppAgeWeightMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/age/lpp_age_200_5_20190116").getPath(),
            200, 5, "utf-8");

    private final static RealMatrix auditModelMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/age/model_audit_5_1_20190116").getPath(),
            5, 1, "utf-8").transpose();

    private final static RealMatrix childModelMatrix = MatrixUtil.getLppMatrix(
            Thread.currentThread().getContextClassLoader().getResource("models/age/model_child_5_1_20190116").getPath(),
            5, 1, "utf-8").transpose();

    @NotNull
    @Column(name = "age")
    @Enumerated(EnumType.STRING)
    private Age age;

    @NotNull
    @Column(name = "sex")
    @Enumerated(EnumType.STRING)
    private Gender sex;

    @Transient
    private VoicePrintResourceType resourceType;

    public VoicePrintFeature(VoicePrintResourceType vpModelVersion, MlvModelData mlvModelData) {
        this.resourceType = vpModelVersion;
        //PNCC类型只是为了做声纹聚类，不需要进行特征获取
        if (vpModelVersion == VoicePrintResourceType.PNCC) {
            return;
        }

        getGender(mlvModelData);
        getAge(mlvModelData);
    }

    private void getGender(MlvModelData mlvModelData) {
        // TODO
        double[] lppSexIvector = VoicePrintModelMatrixService.lppReduceDimension(mlvModelData, lppSexWeightMatrix);

        float maleScore = MatrixUtil.getCosineDistance(lppSexIvector, maleModelMatrix.getRow(0));
        float femaleScore = MatrixUtil.getCosineDistance(lppSexIvector, femaleModelMatrix.getRow(0));
        if (maleScore > femaleScore) {
            sex = Gender.Male;
        } else {
            sex = Gender.Female;
        }
    }

    private void getAge(MlvModelData mlvModelData) {
        // TODO
        double[] lppAgeIvector = VoicePrintModelMatrixService.lppReduceDimension(mlvModelData, lppAgeWeightMatrix);

        float childScore = MatrixUtil.getCosineDistance(lppAgeIvector, childModelMatrix.getRow(0));
        float auditScore = MatrixUtil.getCosineDistance(lppAgeIvector, auditModelMatrix.getRow(0));
        if (childScore > auditScore) {
            age = Age.CHILD;
        } else {
            age = Age.MIDDLE;
        }
    }

    public boolean valid() {
        if (resourceType == VoicePrintResourceType.PNCC) {
            return true;
        }

        return sex != null && age != null;
    }
}